<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>13-物体运动</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
  </style>
</head>

<body>
  <script type="module">
    // 引入three.js
      import * as THREE from "three";
      //引入物理引擎cannon
      import * as Cannon from "cannon";
      import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

      //创建场景
      const scene = new THREE.Scene();

      //创建相机
      const camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        0.1,
        1000
      );
      //设置相机位置
      camera.position.set(0, 10, 40); //统一设置
      //设置相机朝向点位
      camera.lookAt(0, 0, 0);

      //创建渲染器
      const renderer = new THREE.WebGLRenderer({
        antialias: true, //减少边缘齿轮
      });
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.shadowMap.enabled = true; //开启阴影投射
      document.body.appendChild(renderer.domElement);

      const light = new THREE.DirectionalLight(0xffffff, 1);
      light.position.set(5, 10, 7.5);
      scene.add(light);

      //创建结构-几何体
      //创建地面
      const plane = new THREE.Mesh(
        new THREE.PlaneGeometry(20, 20),
        new THREE.MeshPhongMaterial({ color: 0x5ecd71 })
      );
      plane.rotation.x = -Math.PI / 2;
      scene.add(plane);

      //创建小球
      const radius = 1 //半径
      const sphere = new THREE.Mesh(
        new THREE.SphereGeometry(radius, 32, 32),
        new THREE.MeshPhongMaterial({ color: 0xff0000 })
      );
      sphere.position.set(0, 10, 0);
      scene.add(sphere);

      //创建物理世界
      const world = new Cannon.World();
      world.gravity.set(0, -9.8, 0); //设置重力
      
      //创建物理材料
      const groundMaterial = new Cannon.Material('groundMaterial')
      const sphereMaterial = new Cannon.Material('sphereMaterial')
      const contactMaterial = new Cannon.ContactMaterial(
        groundMaterial,
        sphereMaterial,
        {
          restitution:0.6, //值越大反弹越高
        }
      )
      world.addContactMaterial(contactMaterial)

      //创建物理地面
      const groundBody = new Cannon.Body({
        mass: 0, //物体的质量
        shape: new Cannon.Plane(), //物体的形状
        material:groundMaterial
      });
      groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);//旋转角度
      world.addBody(groundBody);

      //创建物理小球
      const sphereBody = new Cannon.Body({
        mass:1,
        shape: new Cannon.Sphere(radius),//形状
        position: sphere.position,//位置 与实体小球保持一致
        material: sphereMaterial
      })
      world.addBody(sphereBody)

      //实时更新物理状态
      const updatePhysic = () => {
        world.step(1/60)
        sphere.position.copy(sphereBody.position)
      }

      //控制插件
      const controls = new OrbitControls(camera, renderer.domElement);
      controls.enableDamping = true; //开启惯性,需要和update方法配合使用

      //动画函数
      function animate() {
        updatePhysic()
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
      }
      animate();
    </script>
</body>

</html>